/*
 * @(#)CheckNameDuplicatedInterceptor.java
 *
 * Copyright 2012 by ShenY BIS, All rights reserved.
 */

package com.bis.framework.interceptor;

import java.lang.reflect.Method;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import java.util.StringTokenizer;

import javax.servlet.http.HttpServletRequest;

import org.apache.log4j.Logger;
import org.apache.struts2.ServletActionContext;
import org.apache.struts2.dispatcher.StrutsRequestWrapper;

import com.bis.framework.annotation.NameAnnotation;
import com.bis.framework.base.action.BaseAction;
import com.bis.framework.base.service.Service;
import com.bis.framework.exception.entity.ExecuteResult;
import com.bis.framework.util.common.MessagesUtil;
import com.bis.framework.util.common.SpringContextUtil;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.MethodFilterInterceptor;
import com.opensymphony.xwork2.util.WildcardHelper;

/**
 * CheckNameDuplicatedInterceptor
 * 
 * @author BIS 2012-12-24
 */
public class CheckNameDuplicatedInterceptor extends MethodFilterInterceptor
{
    /**
     * Version Id
     */
    private static final long   serialVersionUID  = 1L;

    /**
     * Logger
     */
    private static final Logger logger            = Logger.getLogger(CheckNameDuplicatedInterceptor.class);
    /**
     * DEFAULT_DELIMITER
     */
    private static final String DEFAULT_DELIMITER = ",";
    /**
     * namePatterns
     */
    protected String            namePatterns;
    /**
     * namePatternSet
     */
    protected Set               namePatternSet    = Collections.EMPTY_SET;
    /**
     * commonService
     */
    private Service             commonService     = null;

    /**
     * doIntercept
     */
    @Override
    protected String doIntercept(ActionInvocation invocation) throws Exception
    {

        BaseAction action = (BaseAction) invocation.getAction();
        logger.debug("in CheckNameDuplicatedInterceptor: " + action.getClass());
        Method method = null;
        NameAnnotation methodElement = null;
        if (action != null)
        {
            method = getActionMethod(action.getClass(), invocation.getProxy().getMethod());
            methodElement = (NameAnnotation) method.getAnnotation(NameAnnotation.class);
            if (methodElement == null)
            {
                return invocation.invoke();
            }
        }
        try
        {
            //取得需要校验的名称字段
            String targetCode = methodElement.targetCode();
            String targetoriginalityCode = methodElement.targetoriginalityCode();
            //取得需要校验的对象的类型
            Class targetClass = methodElement.targetClass();
            //取得需要校验的名称的值
            ActionContext ac = invocation.getInvocationContext();
            HttpServletRequest request = (HttpServletRequest) ac.get(ServletActionContext.HTTP_REQUEST);
            //Get the html name attribute of the entity
            StrutsRequestWrapper multiWrapper = (StrutsRequestWrapper) request;
            //校验名称是否重复
            if (null != targetCode)
            {
                commonService = (Service) SpringContextUtil.getCtx().getBean("commonService");

                String inputValue = multiWrapper.getParameter(targetCode);
                String originalityValue = multiWrapper.getParameter(targetoriginalityCode);
                if (null != inputValue)
                {
                    inputValue = inputValue.trim();
                }
                logger.debug("original value: " + inputValue);
                if (null != inputValue && !"".equals(inputValue))
                {

                    Integer count = commonService.checkNameDuplication(targetClass, inputValue, originalityValue);
                    if (count > 0)
                    {
                        ExecuteResult executeResult = new ExecuteResult();
                        executeResult.setType(ExecuteResult.VALIDATE_ERROR);
                        String msg = MessagesUtil.getMessage("system004", "default", new Object[]
                        { "[" + inputValue + "]" });
                        executeResult.setMessage(msg);
                        executeResult.setPageComponentId(targetCode);
                        action.setExecuteResult(executeResult);
                        return "nameCheck";
                    }
                }
            }
            return invocation.invoke();
        }
        catch (RuntimeException e)
        {
            logger.error("异常信息：", e);
            throw e;
        }
    }

    /**
     * Compare name with configure patterns, find match result
     * @return
     */
    private boolean namePatternContains(String name)
    {
        name = name.toLowerCase();
        // quick check to see if any actual pattern matching is needed
        boolean needsPatternMatch = false;
        Iterator quickIter = namePatternSet.iterator();
        while (quickIter.hasNext())
        {
            String pattern = (String) quickIter.next();
            if (pattern.equals("*"))
                return false;
            if (pattern.contains("*"))
            {
                needsPatternMatch = true;
            }
        }
        if (!needsPatternMatch)
        {
            return namePatternSet.contains(name);
        }

        WildcardHelper wildcard = new WildcardHelper();
        Iterator iter = namePatternSet.iterator();
        while (iter.hasNext())
        {
            String pattern = (String) iter.next();
            pattern = pattern.toLowerCase();
            if (pattern.contains("*"))
            {
                int[] compiledPattern = wildcard.compilePattern(pattern);
                HashMap<String, String> matchedPatterns = new HashMap<String, String>();
                boolean matches = wildcard.match(matchedPatterns, name, compiledPattern);
                if (matches)
                {
                    return true;
                }
            }
            else
            {
                if (pattern.equalsIgnoreCase(name))
                {
                    return true;
                }
            }
        }
        return false;
    }

    /**
     * Set the configurate name patterns into set
     * @param delimitedString
     * @return
     */
    private Set getDelimitedValues(String delimitedString)
    {
        Set<String> delimitedValues = new HashSet<String>();
        if (delimitedString != null)
        {
            StringTokenizer stringTokenizer = new StringTokenizer(delimitedString, DEFAULT_DELIMITER);
            while (stringTokenizer.hasMoreTokens())
            {
                String nextToken = stringTokenizer.nextToken().toLowerCase().trim();
                if (nextToken.length() > 0)
                {
                    delimitedValues.add(nextToken);
                }
            }
        }
        return delimitedValues;
    }

    /**
     * getActionMethod
     * @Description:
     * @param actionClass
     * @param methodName
     * @return
     * @throws NoSuchMethodException
     */
    protected Method getActionMethod(Class actionClass, String methodName) throws NoSuchMethodException
    {
        Method method;
        try
        {
            method = actionClass.getMethod(methodName, new Class[0]);
        }
        catch (NoSuchMethodException e)
        {
            // hmm -- OK, try doXxx instead
            try
            {
                String altMethodName = "do" + methodName.substring(0, 1).toUpperCase() + methodName.substring(1);
                method = actionClass.getMethod(altMethodName, new Class[0]);
            }
            catch (NoSuchMethodException e1)
            {
                // throw the original one
                throw e;
            }
        }
        return method;
    }

    /**
     * @return the namePatterns
     */
    public String getNamePatterns()
    {
        return namePatterns;
    }

    /**
     * @param namePatterns the namePatterns to set
     */
    public void setNamePatterns(String namePatterns)
    {
        this.namePatterns = namePatterns;
        namePatternSet = getDelimitedValues(namePatterns);
    }

    /**
     * @return the namePatternSet
     */
    public Set getNamePatternSet()
    {
        return namePatternSet;
    }

    /**
     * @param namePatternSet the namePatternSet to set
     */
    public void setNamePatternSet(Set namePatternSet)
    {
        this.namePatternSet = namePatternSet;
    }

    /**
     * @return the commonService
     */
    public Service getCommonService()
    {
        return commonService;
    }

    /**
     * @param commonService the commonService to set
     */
    public void setCommonService(Service commonService)
    {
        this.commonService = commonService;
    }

}
